﻿using MvvmCross.Core.ViewModels;
using Sidvall.UI.Entities;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Sidvall.UI.ViewModels
{
    public abstract class FilterControlViewModelBase<TList, TEntity, TParameter> : ControlViewModelBase
        where TList : BusinessBaseCollection<TEntity>, new()
        where TEntity : BusinessBase
        where TParameter : Sidvall.UI.Messaging.FilterParameter
    {
        #region Public Members

        public event System.EventHandler<Sidvall.UI.ViewModels.FilterControlAction> FilterAction;

        protected abstract Task<long> DeleteItemsAsync();
        protected abstract Task<TList> GetItemsAsync();

        #region Items

        private TList _Items;
        public TList Items
        {
            get
            {
                return _Items;
            }
            private set
            {
                _Items = value;
                RaisePropertyChanged(nameof(Items));
                if (value != null)
                    this.PageItem.TotalRowCount = value.TotalRowCount;
                OnFilterAction(Sidvall.UI.ViewModels.FilterControlAction.ItemsLoaded);
            }
        }

        #endregion
        #region ActiveItem

        private TEntity _ActiveItem;
        public TEntity ActiveItem
        {
            get
            {
                return _ActiveItem;
            }
            set
            {
                _ActiveItem = value;
                RaisePropertyChanged(nameof(ActiveItem));
                RaisePropertyChanged(nameof(CanEdit));
                OnFilterAction(Sidvall.UI.ViewModels.FilterControlAction.ActiveItemChanged);
                OnFilterAction(Sidvall.UI.ViewModels.FilterControlAction.CanDeleteChanged);
                OnFilterAction(Sidvall.UI.ViewModels.FilterControlAction.CanEditChanged);
            }
        }

        #endregion
        #region SelectedItems

        private TList _SelectedItems;
        public TList SelectedItems
        {
            get
            {
                if (_SelectedItems == null)
                    this.SelectedItems = new TList();
                return _SelectedItems;
            }
            protected set
            {
                if (_SelectedItems != null)
                    _SelectedItems.CollectionChanged -= OnSelectedItemsChanged;
                _SelectedItems = value;
                if (_SelectedItems != null)
                    _SelectedItems.CollectionChanged += OnSelectedItemsChanged;
                RaisePropertyChanged(nameof(SelectedItems));
                RaisePropertyChanged(nameof(CanDelete));
            }
        }

        #endregion
        #region RowCountOptions

        private Sidvall.UI.Entities.SelectableKeyValueCollection<string, int> _RowCountOptions;
        public Sidvall.UI.Entities.SelectableKeyValueCollection<string, int> RowCountOptions
        {
            get
            {
                if (_RowCountOptions == null)
                    this.RowCountOptions = Sidvall.UI.Entities.SelectableKeyValueManager.CreateFromValues(false, 25, 50, 100, 200, 500, 1000);
                return _RowCountOptions;
            }
            protected set
            {
                _RowCountOptions = value;
                RaisePropertyChanged(nameof(RowCountOptions));
            }
        }

        #endregion
        #region PageItem

        private PageItem _PageItem;
        public PageItem PageItem
        {
            get
            {
                if (_PageItem == null)
                {
                    this.PageItem = new PageItem()
                    {
                        DescriptionFormat = Sidvall.Resources.ResourceKeyManager.Current.PageItemDescription,
                    };
                }
                return _PageItem;
            }
            protected set
            {
                _PageItem = value;
                RaisePropertyChanged(nameof(PageItem));
            }
        }

        #endregion
        #region FilterParameter

        private TParameter _FilterParameter;
        public TParameter FilterParameter
        {
            get
            {
                return _FilterParameter;
            }
            protected set
            {
                _FilterParameter = value;
                RaisePropertyChanged(nameof(FilterParameter));
            }
        }

        #endregion
        #region CanDelete

        public virtual bool CanDelete
        {
            get
            {
                if (this.FilterParameter?.AllowDelete != true)
                    return false;
                return true;
            }
        }

        #endregion
        #region CanEdit

        public virtual bool CanEdit
        {
            get
            {
                if (this.FilterParameter?.AllowEdit != true)
                    return false;
                return true;
            }
        }

        #endregion

        // Commands
        #region Load

        public ICommand LoadCommand
        {
            get
            {
                return new MvxCommand(async () => await LoadItemsAsync());
            }
        }
        public async Task LoadItemsAsync()
        {
            try
            {
                using (var busyManager = new Sidvall.Data.BusyManager(this))
                {
                    var items = await GetItemsAsync();
                    this.Items = items;
                }
            }
            catch (System.Exception ex)
            {
                await LogAsync(ex);
                await Sidvall.UI.SystemContext.Current.DialogManager.ShowDialogErrorMessageAsync(ex);
            }
        }

        #endregion
        #region Delete

        public ICommand DeleteCommand
        {
            get
            {
                return new MvxCommand(async () => await DeleteAsync());
            }
        }
        public async Task DeleteAsync()
        {
            if (!this.CanDelete)
                return;
            try
            {
                var message = await Sidvall.UI.SystemContext.Current.DialogManager.ShowYesNoMessageAsync("Ta bort " + this.SelectedItems.Count.ToString() + " företag", "Är du säker?",
                    Sidvall.UI.Dialogs.MessageType.Question, false);
                if (message == null)
                    return;
                if (!message.AnswerIsYes)
                    return;
                using (var busyManager = new Sidvall.Data.BusyManager(this))
                {
                    var result = await DeleteItemsAsync();
                }
                await LoadItemsAsync();
            }
            catch (System.Exception ex)
            {
                await LogAsync(ex);
                await Sidvall.UI.SystemContext.Current.DialogManager.ShowDialogErrorMessageAsync(ex);
            }
        }

        #endregion
        #region EditSelectedItem

        public ICommand EditSelectedItemCommand
        {
            get
            {
                return new MvxCommand(EditSelectedItem);
            }
        }
        public void EditSelectedItem()
        {
            if (!this.CanEdit)
                return;
            OnFilterAction(Sidvall.UI.ViewModels.FilterControlAction.EditActiveItem);
        }

        #endregion
        #region PageChanged

        public ICommand PageChangedCommand
        {
            get
            {
                return new MvxCommand(async () => await PageChangedAsync());
            }
        }
        public async Task PageChangedAsync()
        {
            await LoadItemsAsync();
        }

        #endregion
        #region ResetFilter

        public ICommand ResetFilterCommand
        {
            get
            {
                return new MvxCommand(async () => await ResetFilterAsync());
            }
        }
        public async Task ResetFilterAsync()
        {
            try
            {
                using (var busyManager = new Sidvall.Data.BusyManager(this))
                {
                }
            }
            catch (System.Exception ex)
            {
                await LogAsync(ex);
                await Sidvall.UI.SystemContext.Current.DialogManager.ShowDialogErrorMessageAsync(ex);
            }
            await LoadItemsAsync();
        }

        #endregion

        // Viewmodel
        #region InitializeAsync

        public async Task InitializeAsync(TParameter item)
        {
            this.FilterParameter = item;
            if (this.FilterParameter.PreloadList)
            {
                await LoadItemsAsync();
            }
        }

        #endregion
        #region UnloadViewModel

        protected override void UnloadViewModel()
        {
            if (this.SelectedItems != null)
            {
                this.SelectedItems = null;
            }
            base.UnloadViewModel();
        }

        #endregion

        #region OnIsBusyChanged

        protected override void OnIsBusyChanged()
        {
            OnFilterAction(Sidvall.UI.ViewModels.FilterControlAction.IsBusyChanged);
        }

        #endregion
        #region OnSelectedItemsChanged

        private void OnSelectedItemsChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            OnFilterAction(Sidvall.UI.ViewModels.FilterControlAction.SelectedItemsChanged);
        }

        #endregion
        #region OnFilterAction

        private void OnFilterAction(FilterControlAction action)
        {
            if (this.FilterAction != null)
                this.FilterAction(this, action);
        }

        #endregion

        #endregion
        #region Private Members

        #region LogManager

        private Sidvall.Logging.LogManager LogManager
        {
            get
            {
                return Sidvall.SystemContext.Current.LogManager;
            }
        }

        #endregion

        #region LogAsync

        private async Task LogAsync(System.Exception exception)
        {
            if (this.LogManager != null)
                await this.LogManager.WriteAsync(exception, Sidvall.Logging.LogCategories.Application);
        }

        #endregion

        #endregion
        #region Constructors

        protected FilterControlViewModelBase()
        {
        }

        #endregion
    }
}
